import java.util.ArrayList;

import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader.Array;

import info.gridworld.actor.Actor;
import info.gridworld.grid.BoundedGrid;
import info.gridworld.grid.Grid;
import info.gridworld.grid.Location;
import info.gridworld.grid.UnboundedGrid;

/**
 * Character class that allows us to create monsters and player characters.
 * Specifies their stats, as well as player movement on the battle and world
 * map.
 * 
 * @author Michael Chang, Lokman Chu, Alvin Chew
 * @version May 27, 2014
 * @author Period: 5
 * @author Assignment: ZGame
 * 
 * @author Sources: TODO
 */
public class Character extends Actor
{
    private int HP;

    private int MP;

    private int STR;

    private int END;

    private int DEX;

    private int WIL;

    private int DEF;

    private int SPD;

    private int LVL;

    private String Name;

    private int currentHP;

    private int currentMP;

    private AttackMessage ATK;


    /**
     * Base template for all moving entities. "Character Sheet"
     * 
     * @param name
     *            String name
     * @param str
     *            Int Strength
     * @param end
     *            Int Endurance
     * @param dex
     *            Int Dexterity
     * @param wil
     *            Int Willpower
     */
    public Character(
        String name,
        int str,
        int end,
        int dex,
        int wil,
        int spd,
        int lvl )
    {
        Name = name;
        STR = str;
        END = end;
        DEX = dex;
        WIL = wil;
        SPD = spd;
        LVL = lvl;
        DEF = 0;
        HP = end * 10;
        MP = wil * 10;
        currentHP = HP;
        currentMP = MP;
    }


    // movement methods
    /**
     * turns the Actor North, then moves it one space
     */
    public void moveUp()
    {
        moveUp( 1 );
    }


    /**
     * turns the Actor north, then moves i moves
     * 
     * @param i
     *            int i is the amount of moves made
     */
    public void moveUp( int i )
    {
        setDirection( Location.NORTH );
        moveForward( i );
    }


    /**
     * turns the Actor South, then moves it one space
     */
    public void moveDown()
    {
        moveDown( 1 );
    }


    /**
     * turns the Actor north, then moves i moves
     * 
     * @param i
     *            int i is the amount of moves made
     */
    public void moveDown( int i )
    {
        setDirection( Location.SOUTH );
        moveForward( i );
    }


    /**
     * turns the Actor West, then moves it one space
     */
    public void moveLeft()
    {
        moveLeft( 1 );
    }


    /**
     * turns the Actor west, then moves i moves
     * 
     * @param i
     *            int i is the amount of moves made
     */
    public void moveLeft( int i )
    {
        setDirection( Location.WEST );
        moveForward( i );
    }


    /**
     * turns the Actor West, then moves it one space
     */
    public void moveRight()
    {
        moveRight( 1 );
    }


    /**
     * turns the Actor west, then moves i moves
     * 
     * @param i
     *            int i is the amount of moves made
     */
    public void moveRight( int i )
    {
        setDirection( Location.EAST );
        moveForward( i );
    }


    /**
     * Moves Forward
     * 
     * @param i
     *            int i where i is the amount of moves made
     */
    public void moveForward( int i )
    {
        for ( int x = 0; x < i; x++ )
        {
            if ( this.getGrid().isValid( this.getLocation()
                .getAdjacentLocation( this.getDirection() ) )
                && !( ( this.getGrid().get( this.getLocation()
                    .getAdjacentLocation( this.getDirection() ) ) instanceof Character ) || ( this.getGrid()
                    .get( this.getLocation()
                        .getAdjacentLocation( this.getDirection() ) ) instanceof TextCell ) ) )
            {
                this.moveTo( this.getLocation()
                    .getAdjacentLocation( this.getDirection() ) );
            }
        }
    }


    /**
     * Returns all available move locations for the Character
     * 
     * @return ArrayList<Location> list with all allowed move locations
     */
    public ArrayList<Location> getMoveLocations()
    {
        ArrayList<Location> list = new ArrayList<Location>();
        Grid<Actor> g = this.getGrid();

        for ( int r = 0; r < g.getNumRows(); r++ )
        {
            for ( int c = 0; c < g.getNumCols(); c++ )
            {
                Location loc = new Location( r, c );
                if ( this.distance( getLocation(), loc ) <= SPD
                    && !( g.get( loc ) instanceof Character ) )
                {
                    list.add( new Location( r, c ) );
                }
            }
        }

        return list;
    }

    /**
     * Calculates distance between player position and his target location.
     * 
     * @param loc1
     *            starting position
     * @param loc2
     *            target position
     * @return distance
     */
    public int distance( Location loc1, Location loc2 )
    {
        int row = Math.abs( loc1.getRow() - loc2.getRow() );
        int col = Math.abs( loc1.getCol() - loc2.getCol() );

        return row + col;
    }


    /**
     * Changes player or monsters health when damage has been taken.
     * 
     * @param newHP
     */
    public void changeHP( int newHP )
    {
        currentHP = newHP;
    }


    /**
     * Changes player or monsters mana points when skill is cast.
     * 
     * @param newMP
     */
    public void changeMP( int newMP )
    {
        currentMP = newMP;
    }


    /**
     * Changes player or monsters current ATK value.
     * 
     * @param m
     */
    public void changeATK( AttackMessage m )
    {
        ATK = m;
    }


    /**
     * Changes player or monsters current DEF value.
     * 
     * @param newDEF
     */
    public void changeDEF( int newDEF )
    {
        DEF = newDEF;
    }


    // Getter Methods
    /**
     * gets Name of Character
     * 
     * @return String Name
     */
    public String getName()
    {
        return Name;
    }


    /**
     * gets HP value
     * 
     * @return int HP
     */
    public int getHP()
    {
        return HP;
    }


    /**
     * gets MP value
     * 
     * @return int MP
     */
    public int getMP()
    {
        return MP;
    }


    /**
     * gets currentHP value
     * 
     * @return int currentHP
     */
    public int currentHP()
    {
        return currentHP;

    }


    /**
     * gets currentMP value
     * 
     * @return int currentMP
     */
    public int currentMP()
    {
        return currentMP;

    }


    /**
     * gets STR value
     * 
     * @return int STR
     */
    public int getSTR()
    {
        return STR;
    }


    /**
     * gets END value
     * 
     * @return int END
     */
    public int getEND()
    {
        return END;
    }


    /**
     * gets DEX value
     * 
     * @return int DEX
     */
    public int getDEX()
    {
        return DEX;
    }


    /**
     * gets WIL value
     * 
     * @return int WIL
     */
    public int getWIL()
    {
        return WIL;
    }


    /**
     * gets ATK value
     * 
     * @return int ATK
     */
    public AttackMessage getATK()
    {
        return ATK;
    }


    /**
     * gets DEF value
     * 
     * @return int DEF
     */
    public int getDEF()
    {
        return DEF;
    }


    /**
     * gets SPD value
     * 
     * @return int SPD
     */
    public int getSPD()
    {
        return SPD;
    }


    /**
     * gets level of player or monster
     * 
     * @return int LVL
     */
    public int getLevel()
    {
        return LVL;
    }

    // public static void main( String[] args )
    // {
    // Grid<Actor> g = new BoundedGrid<Actor>(10,10);
    // Character c = new Character( "Name", 0, 0, 0, 0, 3 );
    // c.putSelfInGrid( g, new Location(2,2) );
    // ArrayList<Location> list = c.getMoveLocations();
    // for ( Location loc : list )
    // {
    // System.out.println( loc );
    // }
    // }
}
